#ifndef _MMU_H_
#define _MMU_H_

#include "types.h"
#include "err.h"

/*
* Check mmu_get_memory_requirements(...) in mmu.c
* for values explanation
*/
#define MMU_MEM_MIN_SIZE (21 * 1024)
#define MMU_MEM_MIN_ALIGNMENT (16 * 1024)


/*
* Type info for second level tables
*/
#define SECOND_LEVEL_INVALID 0
#define SECOND_LEVEL_COARSE 1
#define SECOND_LEVEL_SECTION 2
#define SECOND_LEVEL_FINE 3

/*
* Domain types
*/
#define DOMAIN_ACCESS_NOT_ALLOWED           0x0
#define DOMAIN_ACCESS_ALWAYS_ALLOWED        0x3
#define DOMAIN_ACCESS_CHECK_PERMIMSSIONS    0x1

/*
* Access permissions
* PRIVILEGE MODE READ ONLY not supported currently
* (It requires setting S/R in CP-15, c1 register appropriately)
*/
#define AP_NO_ACCESS                        0x0
#define AP_PRIV_RW                          0x1
#define AP_PRIV_RW_USER_R                   0x2
#define AP_PRIV_RW_USER_RW                  0x3


/*
* translation table descriptors
*/
#define CREATE_COARSE_TABLE_ENTRY(coarse_tbl_addr, domain) \
  (((uint32_t)coarse_tbl_addr & 0xFFFFFC00) | ((domain & 0xF) <<5) | 0x11)
#define CREATE_SECTION_BASE_ENTRY(section_base, domain, access_permission) \
  (((uint32_t)section_base & 0xFFF00000) | ((access_permission & 0x3) << 10) | \
  ((domain & 0xF) << 5) | 0x12)
#define CREATE_FINE_TABLE_ENTRY(fine_base, domain) \
  (((uint32_t)fine_base & 0xFFFFF000) | ((domain & 0xF) << 5) | 0x13)
#define CREATE_FAULT_ENTRY 0

/*
* Second level descriptors
*/
#define CREATE_LARGE_PAGE_ENTRY(large_page, ap) \
  (((uint32_t)large_page & 0xFFFF0000) | ((ap & 0x3) << 10) | \
  ((ap & 0x3) << 8) | ((ap & 0x3) << 6) | ((ap & 0x3) << 4) | \
  0x1)

#define CREATE_SMALL_PAGE_ENTRY(large_page, ap) \
  (((uint32_t)large_page & 0xFFFFF000) | ((ap & 0x3) << 10) | \
  ((ap & 0x3) << 8) | ((ap & 0x3) << 6) | ((ap & 0x3) << 4) | \
  0x2)


#define CREATE_TINY_PAGE_ENTRY(large_page, ap) \
  (((uint32_t)large_page & 0xFFFFFC00) | ((ap & 0x3) << 4) | 0x3)

/*
* Number of table entries
*/
#define NUM_TT_ENTRIES       4096   // Translation table entries
#define NUM_CP_ENTRIES       256    // Coarse page table entries
#define NUM_FINE_ENTRIES     1024   // Fine page table entries

#define MMU_MIN_PAGE_ALIGNMENT (1024)


/*
* Initialize MMU
* Create page tables in the memory provided
*/
err_t mmu_init(uint8_t *buffer, uint32_t size);

/*
* Create VA-PA mapping
*/
err_t mmu_map_memory(uint8_t *va, uint8_t *pa, uint32_t size);

/*
* Unmap memory
*/
err_t mmu_unmap_memory(uint8_t *va, uint32_t size);
err_t mmu_unmap_all_memory(void);


static inline void mmu_get_memory_requirement(uint32_t *size, uint32_t *alignment)
{
   /*
   * For ARM-962EJ-S processor, the driver needs to maintain 
   * following tables:
   * a) Translation table: Contains 4096 32-bit entries (16KB aligned)
   * b) Coarse page table: Contains 256 32-bit entries (1KB aligned)
   * c) Fine page table: Contains 1024 32-bit entries (4KB aligned)
   *
   * So we ask for 16K + 1K + 4K = 21K memory, aligned at 16K boundar
   * and place tables in order: Translation - Fine - Coarse
   */
   *size = MMU_MEM_MIN_SIZE;
   *alignment = MMU_MEM_MIN_ALIGNMENT;
}

#endif
